package com.woniuxy.service.impl;

import com.github.pagehelper.PageInfo;
import com.woniuxy.entity.*;
import com.woniuxy.entity.DTO.*;
import com.woniuxy.entity.GoodsCommit;
import com.woniuxy.entity.OrderStatus;
import com.woniuxy.entity.Orders;
import com.woniuxy.entity.PaymentMethod;
import com.woniuxy.exception.BusinessException;
import com.woniuxy.mapper.OrdersMapper;
import com.woniuxy.mapper.ShoppingCartsMapper;
import com.woniuxy.producer.DelayProducer;
import com.woniuxy.producer.DirectProducer;
import com.woniuxy.producer.TopicProducer;
import com.woniuxy.service.OrderService;
import com.woniuxy.util.*;
import com.woniuxy.util.PageParam;
import com.woniuxy.util.RabbitMQConst;
import com.woniuxy.util.SnowflakeIdGenerator;
import com.woniuxy.util.UserContext;
import org.jetbrains.annotations.NotNull;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.ParseException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author ：admin
 * @version ：1.0
 * @date ：Created in 2025/5/13 10:36
 * @description ：TODO
 * @modified_by ：
 */
@Service
public class OrderServiceImpl implements OrderService {
    @Resource
    private OrdersMapper ordersMapper;
    @Resource
    private RedisTemplate redisTemplateInit;
    @Resource
    private DirectProducer directProducer;
    @Resource
    private ShoppingCartsMapper shoppingCartsMapper;
    @Resource
    private TopicProducer topicProducer;

    @Resource
    private DelayProducer delayProducer;

    @Resource
    private RedisUtil redisUtil;

    private static String orderId;

    /**
     * <p>从前端页面获取当前页数 pageNum 、每页显示记录数 pageSize 以及查询参数 param ，此处 param 应当为 null 。</p>
     * <p>根据分页参数，查询所有订单信息。</p>
     * @param param 包含 pageNum 、 pageSize 、 param 的参数， param 的泛型为订单类 OrderDTO 。
     * @return 包含查询结果及分页信息的 PageInfo 对象。
     */
    @Override
    public PageInfo<OrderDTO> queryOrderListByPage(PageParam<OrderDTO> param) {
        return PageParam.executePageQuery(param, p -> ordersMapper.selectAllOrders());
    }

    /**
     * <p>查询所有订单状态。</p>
     * @return 订单状态列表
     */
    @Override
    public List<OrderStatus> queryStatusList() {
        return ordersMapper.selectAllStatus();
    }

    /**
     * <p>查询所有支付方式。</p>
     * @return 支付方式列表
     */
    @Override
    public List<PaymentMethod> queryPaymentMethodList() {
        return ordersMapper.selectAllPaymentMethod();
    }

    /**
     * <p>根据条件分页查询订单信息。</p>
     * @param param 分页查询的条件参数
     * @return 包含查询结果和分页信息的 pageInfo 对象
     */
    @Override
    public PageInfo<OrderDTO> queryOrderByCondition(PageParam<OrderDTO> param) {
        return PageParam.executePageQuery(param, p -> ordersMapper.selectOrdersByCondition(param.getParam()));
    }

    /**
     * <p>根据订单编号查询订单详情信息。</p>
     * @param orderId 订单编号
     * @return 订单详情
     */
    @Override
    public OrderDTO queryOrderItemByOrderId(String orderId) {
        // 非空判断
        if (orderId == null) return null;

        // 查询订单商品信息
        List<OrderItemDTO> orderGoodsList = ordersMapper.selectOrderGoodsList(orderId);

        // 查询订单信息
        OrderDTO orderDTO = ordersMapper.selectOrderItemByOrderId(orderId);

        // 将订单商品信息封装到订单信息中
        orderDTO.setOrderItemDTOList(orderGoodsList);

        return orderDTO;
    }

    /**
     * <p>根据被选中的商品生成订单。</p>
     * @param addOrderParamDTOs 被选中的商品
     */
    @Override
    @Transactional
    public void addOrderFromCart(List<AddOrderParamDTO> addOrderParamDTOs) throws InterruptedException, ParseException {
        Integer userId = UserContext.getUserId();
        // 修改购物车商品选中状态
        addOrderParamDTOs.forEach(p -> p.setUserId(userId));
        shoppingCartsMapper.updateSelected(addOrderParamDTOs);
        // 生成订单信息
        Orders orders = getOrders(addOrderParamDTOs);
        // 异步写入数据库
        topicProducer.sendTopic(orders, RabbitMQConst.ADD_ORDERS_ROUTING_KEY);
        redisTemplateInit.opsForHash().delete(CacheConst.USER_ORDER_CACHE, userId + "");
        // 生成订单详情信息
        List<Integer> goodsIds = addOrderParamDTOs
                .stream().map(AddOrderParamDTO::getGoodsId).collect(Collectors.toList());
        List<Goods> goodsList = ordersMapper.selectGoodsListByGoodsIds(goodsIds);
        List<OrderItems> orderItemsList = getOrderItems(addOrderParamDTOs, goodsList, orders);
        topicProducer.sendTopic(orderItemsList, RabbitMQConst.ADD_ORDER_ITEM_LIST_ROUTING_KEY);
    }

    @NotNull
    private static List<OrderItems> getOrderItems(List<AddOrderParamDTO> addOrderParamDTOs,
                                                  List<Goods> goodsList, Orders orders) {
        // 1. 将 goodsList 转换为以商品ID为键的哈希表
        Map<Integer, Goods> goodsMap = goodsList.stream()
                .collect(Collectors.toMap(Goods::getId,
                        Function.identity(),
                        (existing, replacement) -> existing // 选择保留已有值
                ));

        // 2. 遍历 addOrderParamDTOs，直接通过哈希表查找商品
        return addOrderParamDTOs.stream()
                .map(dto -> {
                    Goods goods = goodsMap.get(dto.getGoodsId());
                    if (goods == null) return null; // 忽略无效商品ID
                    OrderItems item = new OrderItems();
                    item.setOrderId(orders.getOrderId());
                    item.setProductId(goods.getId());
                    item.setProductName(goods.getName());
                    item.setProductPrice(goods.getPrice());
                    item.setQuantity(dto.getQuantity());
                    item.setItemAmount(goods.getPrice().multiply(new BigDecimal(dto.getQuantity())));
                    return item;
                })
                .filter(Objects::nonNull) // 过滤空值
                .collect(Collectors.toList());
    }

    /**
     * <p>提交订单</p>
     *
     * @param submitOrderDTO
     * @return
     */
    @Override
    public String submitOrder(SubmitOrderDTO submitOrderDTO) throws ParseException {
        submitOrderDTO.setUserId(UserContext.getUserId());
        submitOrderDTO.setOrderId(orderId);
        ordersMapper.updateSubmitOrder(submitOrderDTO);
        // 用户确认提交订单后，发送延迟消息到队列
        delayProducer.sendDelayMessage(orderId, 60 * 1000);
        redisTemplateInit.opsForHash().delete(CacheConst.USER_ORDER_CACHE, submitOrderDTO.getUserId() + "");
        return orderId;
    }

    /**
     * <p>支付</p>
     *
     * @param orderId
     * @return
     */
    @Override
    public ResponseData<?> pay(String orderId) throws ParseException {
        Integer userId = UserContext.getUserId();
        Integer status = ordersMapper.selectOrderStatus(userId, orderId);
        if (status.equals(1)) {
            ordersMapper.updatePayOrder(userId, orderId);
            ordersMapper.deleteShoppingCartByUserId(userId);
            // 根据用户订单地址计算发货仓库，不考虑用户所在区域没有仓库的情况（此情况下，用户所在地区暂不支持此程序）
            Integer addressId = ordersMapper.selectOrderAddressByOrderId(orderId);
            List<Integer> wareHouseIds = ordersMapper.selectWareHouseIdByAddressId(addressId);
            // 考虑一个地区有多个仓库，不使用算法的情况下，利用随机数选择发货仓库
            int index = new Random().nextInt(wareHouseIds.size());
            Integer wareHouseId = wareHouseIds.get(index);
            // 生成一个分拣订单
            ordersMapper.insertSorting(orderId, wareHouseId);
            return ResponseData.success();
        } else if (status.equals(7)) {
            return ResponseData.fail(ResponseEnum.OUT_OF_PAY_TIME);
        }
        redisTemplateInit.opsForHash().delete(CacheConst.USER_ORDER_CACHE, userId + "");
        return ResponseData.fail(ResponseEnum.FAIL);
    }

    /**
     * <p>立即购买对应的添加订单</p>
     *
     * @param goodsId
     * @return
     */
    @Override
    public String addOrderForCommonGoods(Integer goodsId) throws ParseException, InterruptedException {
        Goods goods = ordersMapper.selectGoodsByGoodsId(goodsId);
        // 添加订单信息
        Orders orders = new Orders();
        orders.setUserId(UserContext.getUserId());
        orderId = new SnowflakeIdGenerator().nextId() + "";
        orders.setOrderId(orderId);
        BigDecimal totalAmount = goods.getPrice();
        orders.setTotalAmount(totalAmount);
        BigDecimal deliveryFee = new BigDecimal(10);
        orders.setDeliveryFee(deliveryFee);
        BigDecimal actualAmount = totalAmount.add(deliveryFee);
        orders.setActualAmount(actualAmount);
        ordersMapper.insertOrdersForCommonGoods(orders);

        // 添加订单详情信息
        OrderItems orderItems = new OrderItems();
        orderItems.setOrderId(orderId);
        orderItems.setProductId(goodsId);
        orderItems.setProductName(goods.getName());
        orderItems.setProductPrice(totalAmount);
        orderItems.setQuantity(1);
        orderItems.setItemAmount(totalAmount.multiply(new BigDecimal(1)));
        ordersMapper.insertOrderItemForCommonGoods(orderItems);
        return orderId;
    }

    @Override
    public List<GoodsImageSrcDTO> queryImgSrc(String orderId) {
        return ordersMapper.queryImgSrc(orderId);
    }

    @Override
    public ResponseData addComment(CommitdDTO commitdDTO) throws ParseException {
        Integer userId = UserContext.getUserId();
        List<GoodsCommit> goodsCommitDTOS = commitdDTO.getOrders();
        for (GoodsCommit goodsCommitDTO : goodsCommitDTOS) {
            goodsCommitDTO.setUserId(userId);
            goodsCommitDTO.setGoodsId(goodsCommitDTO.getProductId());
        }
        ordersMapper.addComment(goodsCommitDTOS);
        ordersMapper.updateStatus(userId, commitdDTO.getOrderId());
        redisTemplateInit.delete(CacheConst.USER_ORDER_CACHE);
        return ResponseData.success();
    }

    /**gi
     * <p>生成订单信息的方法。</p>
     *
     * @param addOrderParamDTOs 被选中的商品
     * @return 订单信息
     * @throws InterruptedException 订单编号生成失败时抛出
     * @throws ParseException       用户ID获取失败时抛出
     */
    private Orders getOrders(List<AddOrderParamDTO> addOrderParamDTOs) throws InterruptedException, ParseException {
        Orders orders = new Orders();
        orderId = String.valueOf(new SnowflakeIdGenerator().nextId());
        orders.setOrderId(orderId);
        Integer userId = UserContext.getUserId();
        //Integer userId = 1;
        orders.setUserId(userId);
        addOrderParamDTOs.forEach(p -> p.setUserId(userId));
        BigDecimal totalAmount = ordersMapper.selectTotalAmount(userId);
        orders.setTotalAmount(totalAmount);
        BigDecimal deliveryFee = new BigDecimal(10);
        orders.setDeliveryFee(deliveryFee);
        BigDecimal actualAmount = totalAmount.add(deliveryFee);
        orders.setActualAmount(actualAmount);
        return orders;
    }

    @Override
    public List<OrderUserDTO> queryOrderByStatus(Integer index) throws ParseException {
        List<Integer> indexs = new ArrayList<>();
        if (index==0 ||index==1){
            indexs.add(index);
        } else if (index==2){
            indexs.addAll(Arrays.asList(2,3,4,7));
        }else if (index==3){
            indexs.addAll(Arrays.asList(5,8));
        }
        //根据jwt获得用户id
        Integer userId = UserContext.getUserId();
        //缓存
        List<OrderUserDTO> cachedOrders = (List<OrderUserDTO>) redisTemplateInit
                .opsForHash()
                .get(CacheConst.USER_ORDER_CACHE, userId + "");
        // 缓存存在且为全量数据（index=0）
        if (index == 0 && cachedOrders != null) {
            return cachedOrders.isEmpty() ? Collections.emptyList() : cachedOrders;
        }
        // 处理缓存穿透：缓存空值
        if (cachedOrders != null && cachedOrders.isEmpty()) {
            return Collections.emptyList();
        }
        // 分布式锁键
        String lockKey = "LOCK:" + CacheConst.USER_ORDER_CACHE + ":" + userId;
        try {
            // 尝试获取锁
            if (redisUtil.tryLock(lockKey, "locked", 30)) {
                // 双重检查缓存
                cachedOrders = (List<OrderUserDTO>) redisTemplateInit
                        .opsForHash()
                        .get(CacheConst.USER_ORDER_CACHE, userId + "");
                if (cachedOrders != null) {
                    return filterOrders(cachedOrders, indexs);
                }

                // 查询数据库
                List<OrderUserDTO> orderUserDTOS = ordersMapper.queryOrderByStatus(indexs, userId);
                if (orderUserDTOS == null || orderUserDTOS.isEmpty()) {
                    // 缓存空值，过期时间5分钟
                    redisTemplateInit.opsForHash().put(CacheConst.USER_ORDER_CACHE, userId + "", Collections.emptyList());
                    redisTemplateInit.expire(CacheConst.USER_ORDER_CACHE, 5, TimeUnit.MINUTES);
                    return Collections.emptyList();
                }

                // 处理图片等逻辑...
                List<String> orderIds = new ArrayList<>();
                //获取订单id
                for (OrderUserDTO orderUserDTO : orderUserDTOS) {
                    orderIds.add(orderUserDTO.getOrderId());
                }
                //获取订单图片集合
                List<GoodsImageSrcDTO> goods = ordersMapper.queryOrderImage(orderIds);
                //将图片集合添加到订单集合中
                for (OrderUserDTO orderUserDTO : orderUserDTOS){
                    List<GoodsImageSrcDTO> list = new ArrayList<>();
                    for (GoodsImageSrcDTO good : goods) {
                        if (good.getOrderId().equals(orderUserDTO.getOrderId())){
                            list.add(good);
                        }
                    }
                    orderUserDTO.setProducts(list);
                    orderUserDTO.setProductCount(list.size());
                }
                // 设置缓存，过期时间1小时
                redisTemplateInit.opsForHash().put(CacheConst.USER_ORDER_CACHE, userId + "", orderUserDTOS);
                redisTemplateInit.expire(CacheConst.USER_ORDER_CACHE, 1, TimeUnit.HOURS);
                return orderUserDTOS;
            } else {
                // 短暂等待后重试
                Thread.sleep(100);
                return queryOrderByStatus(index);
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            redisUtil.releaseLock(lockKey);
        }
    }

    // 根据indexs过滤订单
    private List<OrderUserDTO> filterOrders(List<OrderUserDTO> orders, List<Integer> indexs) {
        return orders.stream()
                .filter(order -> indexs.contains(order.getOrderStatus()))
                .collect(Collectors.toList());
    }

    @Override
    public void deleteUserOrder(String orderId) throws ParseException {
        String userId = UserContext.getUserId().toString();
        // 第一次删除缓存
        redisTemplateInit.opsForHash().delete(CacheConst.USER_ORDER_CACHE, userId);

        // 发送MQ删除数据库订单
        directProducer.sendDeleteUserOrder(orderId + "_" + userId, RabbitMQConst.DELETE_USER_ORDER);

        // 延迟1秒后再次删除缓存，延迟时间可根据业务调整
        try {
            Thread.sleep(1000);
            redisTemplateInit.opsForHash().delete(CacheConst.USER_ORDER_CACHE, userId);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public OrderItemAndAddressDTO queryOrderItemAndAddressByOrderId(String orderId) {
        OrderItemAndAddressDTO cachedData = (OrderItemAndAddressDTO) redisTemplateInit
                .opsForHash().get(CacheConst.ORDER_DETAIL_CACHE, orderId);

        if (cachedData != null) {
            return cachedData;
        }

        // 使用分布式锁防止击穿
        String lockKey = "LOCK:" + CacheConst.ORDER_DETAIL_CACHE + ":" + orderId;
        try {
            if (redisUtil.tryLock(lockKey, "locked", 30)) {
                // 双重检查
                cachedData = (OrderItemAndAddressDTO) redisTemplateInit.opsForHash()
                        .get(CacheConst.ORDER_DETAIL_CACHE, orderId);
                if (cachedData != null) return cachedData;

                // 查询数据库
                OrderItemAndAddressDTO data = ordersMapper.queryOrderItemByOrderId(orderId);
                if (data == null) {
                    // 缓存空值，过期时间5分钟
                    redisTemplateInit.opsForHash()
                            .put(CacheConst.ORDER_DETAIL_CACHE, orderId, new OrderItemAndAddressDTO());
                    redisTemplateInit.expire(CacheConst.ORDER_DETAIL_CACHE, 5, TimeUnit.MINUTES);
                    return null;
                }

                // 设置缓存并过期
                redisTemplateInit.opsForHash().put(CacheConst.ORDER_DETAIL_CACHE, orderId, data);
                redisTemplateInit.expire(CacheConst.ORDER_DETAIL_CACHE, 1, TimeUnit.HOURS);
                return data;
            } else {
                Thread.sleep(100);
                return queryOrderItemAndAddressByOrderId(orderId);
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            redisUtil.releaseLock(lockKey);
        }
    }

}
